#need some way to make static action options
#menuWriter.py

import sys

def readInput():
    return sys.stdin.readline().strip()

class Option(object):
    def __init__(self, optString, optName):
        self.optString  = optString
        self.optName    = optName
        self.openAction = None
        
    def makeSubMenu(self, title, openAction=None):
        self.subMenu    = Menu(title)
        self.leaf       = False
        self.openAction = openAction
        return self.subMenu

    def makeOptAction(self, aFunc, valRange):
        self.leaf     = True
        self.optFunc  = aFunc
        self.valRange = valRange

    def makeStaticOptAction(self, staticAction):
        self.openAction = staticAction

    def execAction(self, arg):
        if not self.leaf:
            raise "Error: %s is not a executable option" % self.optName
        if isinstance(self.valRange, list):
            if not arg in self.valRange:
                raise "Error: the argument '%s' is not valid for the option %s. It must be be one of the following values %s" % (str(arg), self.optName, str(self.valRange)) 
        else:
            if not self.valRange(arg):
                raise "Error: the argument '%s' is not valid for the option %s" % (str(arg), self.optName)
        return self.optFunc(arg)

    def runOpenAction(self):
        if not self.openAction:
            return None
        return self.openAction()

    def makeActionOptionObj(cls, optString, optName, aFunc, valRange):
        optionObj = cls(optString, optName)
        optionObj.makeOptAction(aFunc, valRange)
        return optionObj
    makeActionOptionObj = classmethod(makeActionOptionObj)

    def makeStaticActionOptionObj(cls, optString, optName, staticAct):
        optionObj = cls(optString, optName)
        optionObj.makeStaticOptAction(staticAct)
        return optionObj
    makeStaticActionOptionObj = classmethod(makeStaticActionOptionObj)

    def makeMenuOptionObj(cls, optString, optName, title, openAction=None):
        optionObj = cls(optString, optName)
        optionObj.makeSubMenu(title, openAction)
        return optionObj
    makeMenuOptionObj = classmethod(makeMenuOptionObj)

class Menu(object):
    def __init__(self, title):
        self.title   = title
        self.options = []

    def addOption(self, aOption):
        aOption.runOpenAction()
        if not isinstance(aOption, Option):
            raise "Error: not a valid option"
        self.options.append(aOption)
        return aOption

    def buildMenuActionOption(self, optString, optName, aFunc, valRange):
        return self.addOption(Option.makeActionOptionObj(optString, optName, aFunc, valRange))

    def buildStaticActionOption(self, optString, optName, staticAct):
        return self.addOption(Option.makeStaticActionOptionObj(optString, optName, staticAct))

    def buildSubMenuOption(self, optString, optName, title, openAction=None):
        return self.addOption(Option.makeMenuOptionObj(optString, optName, title, openAction))

class MenuWriter(object):
    def __init__(self, defMenu):
        self.defMenu = defMenu
        self.startDefMenu()

    def runOption(self, aOption):
        aOption
        if aOption.leaf:
            print "\nEnter a value: "
            aOption.execAction(readInput())
        else:
            self.runMenu(aOption.subMenu)

    def runMenu(self, menu, options=None, topMenu=False):
        if options==None:
            options = menu.options
        titleLen = len(menu.title)
        barStr   = ""
        for i in range((70-titleLen)/2):
            barStr+='-'
        reprintMenu = True
        while reprintMenu:
            print "\n%s%s%s\n" % (barStr, menu.title, barStr)
            for i, option in enumerate(options):
                g = i + 1
                print "(%i) %s\n" % (g, option.optString)
            numOpts = len(options) + 1
            if topMenu:
                print "(%i) Exit" % numOpts
            else:
                print "(%i) Go Back" % numOpts
            print "Please select an option: "
            successfulInput=False
            while(not successfulInput):
                try:
                    opt = int(readInput())
                    successfulInput=True
                except:
                    successfulInput=False
                    print "\nNot a valid option\nEnter Again:"
                if opt<1 or opt>numOpts:
                    successfulInput=False
                    print "\nNot a valid option\nEnter Again:"
            if opt==numOpts:
                if topMenu:
                    sys.exit(0)
                return
            self.runOption(options[opt-1])

    def startDefMenu(self):
        self.runMenu(self.defMenu, topMenu=True)
        
            
            
        
        
        
        
